package com.lqw.wechat.common.util;

import java.io.InputStream;
import java.io.Writer;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;

import com.lqw.wechat.common.config.WeChatAccessConfig;
import com.lqw.wechat.common.config.WeChatRequestConfig;
import com.lqw.wechat.common.response.message.BaseMessageResponse;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.core.util.QuickWriter;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.XppDriver;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

/**
 * Created by luqiwen on 2017/6/16.
 */
public class WeChatUtil {

    private static final String TOKEN="lqw835i46kyl";
    private static final Logger logger=LoggerFactory.getLogger(WeChatUtil.class);

    private WeChatUtil(){}

    /**
     *  校验微信服务器发送过来的参数是否匹配得上设置的 token
     * @param signature
     * @param timestamp
     * @param nonce
     * @return
     */
    public static boolean checkToken(String signature, String timestamp, String nonce){
        String[] arr = new String[] { TOKEN, timestamp, nonce };
        // 将 token、timestamp、nonce 三个参数进行字典序排序
        Arrays.sort(arr);
        StringBuilder content = new StringBuilder();
        for (int i = 0; i < arr.length; i++) {
            content.append(arr[i]);
        }

        String resultStr = null;
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            // 将三个参数字符串拼接成一个字符串进行 sha1 加密
            byte[] digest = md.digest(content.toString().getBytes());
            resultStr = byteToString(digest);
        } catch (NoSuchAlgorithmException e) {
            logger.error("校验微信服务器请求 token 失败，signature:{} , timestamp:{} , nonce:{} ", new Object[]{signature, timestamp, nonce, e});
        }

        // 将 sha1 加密后的字符串可与 signature 对比，标识该请求来源于微信
        return resultStr != null ? Objects.equals(resultStr, signature.toUpperCase()) : Boolean.FALSE;
    }

    public static Map<String,String> xml2Map(InputStream inputStream){
        if(inputStream==null){
            return MapUtils.EMPTY_MAP;
        }
        try {
            Map<String, String> map = new HashMap<>();

            // 读取输入流
            SAXReader reader = new SAXReader();
            Document document = reader.read(inputStream);
            // 得到xml根元素
            Element root = document.getRootElement();
            // 得到根元素的所有子节点
            List<Element> elementList = root.elements();

            // 遍历所有子节点
            for (Element e : elementList)
                map.put(e.getName(), e.getText());

            // 释放资源
            inputStream.close();
            return map;
        }catch (Exception e){
            logger.error("解析微信推送的XML消息失败",e);
            return MapUtils.EMPTY_MAP;
        }

    }

    public static String bean2Xml(BaseMessageResponse message, Class clazz){
        if(message==null){
            logger.error("转换的消息不能为空");
            return null;
        }
        if(clazz==null){
            logger.error("转换的消息类型不能为空");
            return null;
        }
        xstream.alias("xml", clazz);
        return xstream.toXML(message);
    }

    @SuppressWarnings("unused")
    private static XStream xstream = new XStream(new XppDriver() {
        @Override
        public HierarchicalStreamWriter createWriter(Writer out) {
            return new PrettyPrintWriter(out) {
                // 对所有xml节点的转换都增加CDATA标记
                @SuppressWarnings("rawtypes")
                @Override
                public void startNode(String name, Class clazz) {
                    super.startNode(name, clazz);
                }

                @Override
                protected void writeText(QuickWriter writer, String text) {
                    writer.write("<![CDATA[");
                    writer.write(text);
                    writer.write("]]>");
                }
            };
        }
    });

    /**
     * 将字节数组转换为十六进制字符串
     * @param byteArray
     * @return
     */
    private static String byteToString(byte[] byteArray) {
        StringBuilder strDigest = new StringBuilder();
        char[] digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
        for (byte b : byteArray) {
            char[] tempArr={digit[(b >>> 4) & 0X0F], digit[b & 0X0F]};
            strDigest.append(tempArr);
        }
        return strDigest.toString();
    }

}
